# ~*~ coding: utf-8 ~*~
import time
from flask import request, views, render_template, jsonify
from flask_login import current_user

from apps.common.utils import fill_date_to_timestamp, timestamp_obj_to_str, get_remote_address
from apps.common.mixin import CompatibleWithSelect2Mixin
from apps.common import response
from apps.extensions import db
from apps.perms.mixin import PermissionRequiredMixin, LoginRequiredMixin
from apps.assets.models import Asset
from ...models import AdHoc, InventoryGroup, AdhocExecuteLog
from ...forms import AdHocForm, AdhocExecuteForm
from ...tasks import run_adhoc


__all__ = [
    'AdHocListAPI', 'AdHocListView', 'AdHocCreateView',
    'AdHocUpdateView', 'AdHocDeleteView', 'AdHocExecuteView',
    'AdHocExecuteLogAPI', 'AdHocExecuteLogView'
]


class AdHocListAPI(CompatibleWithSelect2Mixin, PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-adhoc-list'

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                # ('name', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        if request.values.get('type') == 'select2':
            filter_conditions, order_by_list, offset, limit = self.select2_queryset()

        adhocs, count = AdHoc.get_queryset(filter_conditions=filter_conditions,
                                           order_by_list=order_by_list,
                                           offset=offset, limit=limit)
        results = list()
        for adhoc in adhocs:
            results.append({
                'id': adhoc.id,
                'name': adhoc.name,
                'args': adhoc.args,
                'create_by': adhoc.create_by,
                'create_time': timestamp_obj_to_str(adhoc.create_time),
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class AdHocListView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-adhoc-list'

    def get(self):
        return render_template('tasks/realtime/adhoc_list.html')


class AdHocUpdateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-adhoc-update'

    def get(self, pk):
        instance = db.session.query(AdHoc).get(pk)
        content = {
            'id': instance.id,
            'name': instance.name,
            'args': instance.args,
        }
        return render_template('tasks/realtime/adhoc_update.html', **content)

    def post(self, pk):
        form = AdHocForm(request.values)
        instance = db.session.query(AdHoc).get(pk)
        if form.validate():
            _clean_data = form.data
            if instance.name != _clean_data.get('name'):
                if db.session.query(AdHoc).filter_by(name=_clean_data.get('name')).count():
                    return response.params_error({
                        'field': 'name',
                        'message': '模块名称不能重复'
                    })

            instance.update(**_clean_data)
            return response.success()
        else:
            return response.params_error(form.get_error())


class AdHocCreateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-adhoc-create'

    def get(self):
        return render_template('tasks/realtime/adhoc_create.html')

    def post(self):
        form = AdHocForm(request.values)
        if form.validate():
            _clean_data = form.data
            if db.session.query(AdHoc).filter_by(name=_clean_data.get('name')).count():
                return response.params_error({
                    'field': 'name',
                    'message': '模块名称不能重复'
                })

            _clean_data['create_by'] = current_user.name
            AdHoc.create(**_clean_data)
            return response.success()
        else:
            return response.params_error(form.get_error())


class AdHocDeleteView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-adhoc-delete'

    def post(self, pk):
        instance = db.session.query(AdHoc).get(pk)
        instance.delete()
        return response.success()


class AdHocExecuteView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-adhoc-execute'

    def get(self):
        pk = request.args.get('pk')
        instance = db.session.query(AdHoc).get(pk)
        content = {
            'id': instance.id,
            'name': instance.name,
            'args': instance.args,
        }
        return render_template('tasks/realtime/adhoc_execute.html', **content)

    def post(self):
        form = AdhocExecuteForm(request.values)
        if form.validate():
            _clean_data = form.data
            module = _clean_data.get('name')
            args = _clean_data.get('args')
            host_ids = _clean_data.get('hosts').split(',')
            group_ids = _clean_data.get('groups').split(',')
            tasks = [dict(action=dict(module=module, args=args))]
            groups = db.session.query(InventoryGroup).filter(InventoryGroup.id.in_(group_ids)).all()
            hosts = db.session.query(Asset).filter(Asset.id.in_(host_ids)).all()

            # log recode
            host_names = [host.hostname for host in hosts]
            group_names = [group.name for group in groups]
            log_dict = {
                'user': "{} ({})".format(current_user.name, current_user.username),
                'remote_ip': get_remote_address(),
                'module': module,
                'args': args,
                'hosts': ','.join(host_names),
                'groups': ','.join(group_names),
                'exec_time':  time.time(),
            }
            log = AdhocExecuteLog.create(**log_dict)
            # run adhoc
            task = run_adhoc.apply_async(args=(hosts, groups, tasks, log), serializer='pickle')
            log.update(celery_id=task.id)
            return response.success(data={'task_id': task.id})
        else:
            return response.params_error(form.get_error())


class AdHocExecuteLogAPI(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-log-adhoc'

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('exec_time', 'gte', start_time),
                ('exec_time', 'lte', end_time),
            ],
            'or': [
                ('name', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        logs, count = AdhocExecuteLog.get_queryset(filter_conditions=filter_conditions,
                                                   order_by_list=order_by_list,
                                                   offset=offset, limit=limit)
        results = list()
        for log in logs:
            result = 'unknown'
            if log.result:
                result = log.result['summary']['success']

            results.append({
                'id': log.id,
                'celery_id': log.celery_id,
                'user': log.user,
                'remote_ip': log.remote_ip,
                'module': log.module,
                'args': log.args,
                'hosts': log.hosts,
                'groups': log.groups,
                'result': result,
                'exec_time': timestamp_obj_to_str(log.exec_time),
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class AdHocExecuteLogView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-log-adhoc'

    def get(self):
        return render_template('tasks/realtime/adhoc_log.html')

